﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace iNet.Tasks
{
	#region Task
	/// <summary>
	/// 工作基底類別。
	/// </summary>
	public abstract class Task : INotifyPropertyChanged
	{
		#region 欄位
		volatile List<WaitEvent> _ActionWaitEvents;
		Task _ChildTask;
		TaskState? _ChildTaskState;
		volatile WaitEvent _CompletionWaitEvent;
		long _DelayedStartTime;
		Exception _Exception;
		TaskExecutionThread _ExecutionThread;
		TaskExecutor _Executor;
		TaskFlags _Flags = TaskFlags.IsPreemptable;
		double? _InitialProgress;
		string _LastMessage;
		TaskMessageType _LastMessageType;
		volatile NLog.Logger _Logger;
		string _Name;
		Task _ParentTask;
		TaskVersion _ParentTaskVersion;
		TaskPriority _Priority = TaskPriority.Normal;
		double? _Progress;
		PropertyChangedEventHandler _PropertyChangedHandlers;
		long? _ReadyTime;
		TaskState _State = TaskState.Initializing;
		object _SyncRoot = new object();
		internal readonly LinkedListNode<Task> TaskQueueNode;
		TaskVersion _Version;
		int _VersionNumber = 1;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 Task 執行個體。
		/// </summary>
		protected Task()
		{
			this.UpdateVersion();
			this.TaskQueueNode = new LinkedListNode<Task>(this);
		}
		#endregion
		#region Cancel
		/// <summary>
		/// 取消工作的執行。
		/// </summary>
		public void Cancel()
		{
			TaskExecutor executor = _Executor;
			if (executor != null)
				executor.CancelTask(this);
		}
		#endregion
		#region CancelInternal
		internal void CancelInternal(bool reset)
		{
			//取消工作
			bool isCanceling = false;
			TaskVersion version = null;
			lock (_SyncRoot)
			{
				//變更狀態
				if (_State == TaskState.Executing)
					this.SetState(TaskState.Canceling);
				else if (_State == TaskState.Ready)
				{
					//變更狀態
					if (reset)
						this.SetState(TaskState.Initializing);
					else
						this.SetState(TaskState.Canceled);

					//更新版本
					this.UpdateVersion();

					//通知父工作
					if (_ParentTask != null && !reset)
					{
						_ParentTask.OnChildTaskCompleted(this, _ParentTaskVersion, TaskState.Canceled);
						_ParentTask = null;
						_ParentTaskVersion = null;
					}

					//重設欄位
					_Executor = null;
				}
				else
					return;

				//更新版本
				//TaskVersion oldVersion = this.UpdateVersion();

				//取消工作
				if (!reset)
				{
					//取消子工作
					if (_ChildTask != null)
						_Executor.CancelTask(_ChildTask);

					//取消動作執行
					if (_ActionWaitEvents != null && _ActionWaitEvents.Count > 0)
					{
						for (int i = _ActionWaitEvents.Count - 1; i >= 0; --i)
							_ActionWaitEvents[i].Set();
						_ActionWaitEvents.Clear();
					}

					//取得狀態
					isCanceling = (_State == TaskState.Canceling);
					version = _Version;
				}
			}

			//通知已取消
			if (isCanceling)
				this.OnCanceling(new TaskEventArgs(this, version));
		}
		#endregion
		#region CurrentTask
		/// <summary>
		/// 取得目前正在執行的工作。
		/// </summary>
		public static Task CurrentTask
		{
			get
			{
				TaskExecutionThread execThread = TaskExecutionThread.CurrentThread;
				return (execThread != null ? execThread.CurrentTask : null);
			}
		}
		#endregion
		#region CurrentVersion
		/// <summary>
		/// 取得目前的工作版本。
		/// </summary>
		protected TaskVersion CurrentVersion
		{
			get
			{
				return _Version;
			}
		}
		#endregion
		#region CreateMessage
		/// <summary>
		/// 建立新的訊息。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="messageType">訊息類型。</param>
		/// <param name="message">訊息內容。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void CreateMessage(TaskVersion version, TaskMessageType messageType, string message)
		{
			//建立訊息
			lock (_SyncRoot)
			{
				//確認
				if (version == null)
					throw new ArgumentNullException("version");
				if (_Version != version || (_State != TaskState.Executing && _State != TaskState.Canceling))
					return;

				//紀錄狀態
				switch (messageType)
				{
					case TaskMessageType.Error:
						_Flags |= TaskFlags.HasErrors;
						break;
					case TaskMessageType.Warning:
						_Flags |= TaskFlags.HasWarnings;
						break;
				}
			}

			//引發事件
			this.MessageCreated.RaiseEvent(this, new TaskMessageEventArgs(this, version, messageType, message));
		}
		#endregion
		#region DelayedStartTime
		/// <summary>
		/// 取得或設定工作延遲的啟動時間，單位為毫秒。
		/// </summary>
		public long DelayedStartTime
		{
			get
			{
				return _DelayedStartTime;
			}
			set
			{
				if (value < 0)
					value = 0;
				this.SetInitializingParameter<long>(ref _DelayedStartTime, value);
			}
		}
		#endregion
		#region DoAction
		/// <summary>
		/// 執行指定的動作，並在超過指定時間後 -或- 工作取消時立即返回。
		/// </summary>
		/// <param name="action">指定的動作。</param>
		/// <param name="timeout">指定的等待時間，單位為毫秒。</param>
		/// <param name="args">動作參數。</param>
		/// <returns>True 表示動作執行完成，False 表示已超過指定等待時間 -或- 工作正在取消中。</returns>
		/// <exception cref="ArgumentNullException">action 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="InvalidOperationException">目前工作狀態不是 Canceling 或 Executing。</exception>
		/// <exception cref="TargetInvocationException">執行動作時發生例外。</exception>
		protected bool DoAction(Delegate action, int timeout, params object[] args)
		{
			//確認參數
			if (action == null)
				throw new ArgumentNullException("action");

			//進入同步區域
			Monitor.Enter(_SyncRoot);

			//確認狀態
			if (_State == TaskState.Canceling)
			{
				Monitor.Exit(_SyncRoot);
				return false;
			}
			if (_State != TaskState.Executing)
			{
				Monitor.Exit(_SyncRoot);
				throw new InvalidOperationException();
			}

			//建立 WaitHandle
			WaitEvent waitEvent = new WaitEvent();
			if (_ActionWaitEvents == null)
				_ActionWaitEvents = new List<WaitEvent>();
			_ActionWaitEvents.Add(waitEvent);

			//執行工作
			object[] param = new object[] { waitEvent, action, args, null };
			ThreadPool.QueueUserWorkItem(DoActionProc, param);

			//等待工作完成
			Monitor.Exit(_SyncRoot);
			try
			{
				//等待工作完成
				if (!waitEvent.Wait(timeout))
					return false;

				//擲出例外
				if (param[3] != null)
					throw new TargetInvocationException(param[3] as Exception);
			}
			finally
			{
				//釋放資源
				lock (_SyncRoot)
				{
					if (_ActionWaitEvents != null)
						_ActionWaitEvents.Remove(waitEvent);
				}
			}

			//完成
			return !this.IsCanceling;
		}
		#endregion
		#region DoActionProc
		void DoActionProc(object param)
		{
			//取得參數
			object[] array = (param as object[]);
			WaitEvent waitEvent = (array[0] as WaitEvent);
			Delegate action = (array[1] as Delegate);
			object[] args = (array[2] as object[]);

			//執行工作
			try
			{
				action.DynamicInvoke(args);
			}
			catch (Exception ex)
			{
				array[3] = ex;
			}

			//通知已完成
			waitEvent.Set();
		}
		#endregion
		#region Exception
		/// <summary>
		/// 取得工作執行時所發生的例外。
		/// </summary>
		public Exception Exception
		{
			get
			{
				return _Exception;
			}
		}
		#endregion
		#region Execute
		internal void Execute(TaskExecutionThread execThread)
		{
			//紀錄執行緒
			_ExecutionThread = execThread;

			//變更狀態
			lock (_SyncRoot)
			{
				//確認
				if (_State != TaskState.Canceling && (_State != TaskState.Ready || !this.ValidateInitParameters()))
				{
					this.SetState(TaskState.Error);
					return;
				}

				//變更狀態
				if (_State == TaskState.Ready)
					this.SetState(TaskState.Executing);
			}

			//執行工作
			try
			{
				if (_State == TaskState.Executing)
				{
					//更新版本
					lock (_SyncRoot)
					{
						this.UpdateVersion();
					}

					//執行工作
					bool succeeded;
					try
					{
						succeeded = this.Execute(_Version);
					}
					catch (Exception ex)
					{
						_Exception = ex;
						succeeded = false;
					}
					finally
					{
						//等待子工作完成
						//this.WaitForChildTask();
					}

					//變更狀態
					lock (_SyncRoot)
					{
						//更新版本
						this.UpdateVersion();

						//變更狀態
						if (_State == TaskState.Executing)
							this.SetState(succeeded ? TaskState.Executed : TaskState.Error);
						else if (_State == TaskState.Canceling)
							this.SetState(TaskState.Canceled);
						else
							this.SetState(TaskState.Error);
					}
				}
				else
				{
					this.SetState(TaskState.Canceled);
				}
			}
			catch (ThreadAbortException ex)
			{
				lock (_SyncRoot)
				{
					if (_State == TaskState.Canceling)
					{
						this.SetState(TaskState.Canceled);
						Thread.ResetAbort();
					}
					else
						this.SetState(TaskState.Error);
				}
			}
			catch (ThreadInterruptedException ex)
			{
				lock (_SyncRoot)
				{
					if (_State == TaskState.Canceling)
						this.SetState(TaskState.Canceled);
					else
						this.SetState(TaskState.Error);
				}
			}

			//通知父工作
			if (_ParentTask != null)
			{
				_ParentTask.OnChildTaskCompleted(this, _ParentTaskVersion, _State);
				_ParentTask = null;
				_ParentTaskVersion = null;
			}

			//結束
			_ExecutionThread = null;
		}
		/// <summary>
		/// 執行工作，並等待其執行完成。
		/// </summary>
		/// <returns>工作完成後的狀態。</returns>
		/// <exception cref="InvalidOperationException">目前的狀態不是 Initializing。</exception>
		public TaskState Execute()
		{
			lock (_SyncRoot)
			{
				if (_Executor == null)
				{
					Task currentTask = Task.CurrentTask;
					TaskExecutor executor = (currentTask != null ? currentTask._Executor : TaskExecutor.DefaultExecutor);
					executor.EnqueueTask(this, true);
				}
			}
			TaskState state;
			this.WaitForCompletion(Timeout.Infinite, out state);
			return state;
		}
		/// <summary>
		/// 執行工作。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <returns>True 表示工作執行成功，False 表示執行失敗。</returns>
		protected abstract bool Execute(TaskVersion version);
		#endregion
		#region ExecuteChildTask
		/// <summary>
		/// 執行子工作，並等待其執行完成。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="childTask">要執行的子工作。</param>
		/// <param name="forwardMessage">是否要將子工作的訊息直接送出，預設值為 True。</param>
		/// <returns>子工作的執行完成後的狀態。</returns>
		/// <exception cref="ArgumentNullException">version 或 childTask 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="InvalidOperationException">目前正在執行其他子工作。</exception>
		protected TaskState ExecuteChildTask(TaskVersion version, Task childTask, bool forwardMessage = true)
		{
			//初始化
			lock (_SyncRoot)
			{
				//確認參數
				if (version == null)
					throw new ArgumentNullException("version");
				if (childTask == null)
					throw new ArgumentNullException("childTask");

				//確認狀態
				if (_Version != version)
					return TaskState.Canceled;
				if (_State != TaskState.Executing && _State != TaskState.Canceling)
					return TaskState.Error;
				if (_ChildTask != null || childTask._ParentTask != null)
					throw new InvalidOperationException();

				//初始化子工作
				if (forwardMessage)
					_Flags |= TaskFlags.ForwardChildTaskMessage;
				else
					_Flags &= ~TaskFlags.ForwardChildTaskMessage;
				_ChildTask = childTask;
				childTask.SetParentTask(this, version);

				//事件連結
				childTask.MessageCreated += this.OnChildTaskMessageCreated;
				childTask.ProgressChanged += this.OnChildTaskProgressChanged;
			}

			//執行子工作
			try
			{
				//將子工作加入佇列
				_Executor.EnqueueTask(childTask);

				//等待子工作完成
				childTask.WaitForCompletion();
				return childTask.State;
			}
			finally
			{
				childTask.MessageCreated -= this.OnChildTaskMessageCreated;
				childTask.ProgressChanged -= this.OnChildTaskProgressChanged;
			}
		}
		#endregion
		#region Executor
		/// <summary>
		/// 取得負責排程及執行此工作的 TaskExecutor。
		/// </summary>
		public TaskExecutor Executor
		{
			get
			{
				return _Executor;
			}
		}
		#endregion
		#region ExecutionThread
		/// <summary>
		/// 取得負責執行此工作的執行緒。
		/// </summary>
		public TaskExecutionThread ExecutionThread
		{
			get
			{
				return _ExecutionThread;
			}
		}
		#endregion
		#region HasErrors
		/// <summary>
		/// 取得工作執行時是否發生錯誤。
		/// </summary>
		public bool HasErrors
		{
			get
			{
				return ((_Flags & TaskFlags.HasErrors) != 0);
			}
		}
		#endregion
		#region HasWarnings
		/// <summary>
		/// 取得工作執行時是否發生警告。
		/// </summary>
		public bool HasWarnings
		{
			get
			{
				return ((_Flags & TaskFlags.HasWarnings) != 0);
			}
		}
		#endregion
		#region InitialProgress
		/// <summary>
		/// 取得或設定工作初始的進度值，預設值為 為 Null (Visual Basic 為 Nothing)。
		/// </summary>
		protected double? InitialProgress
		{
			get
			{
				return _InitialProgress;
			}
			set
			{
				lock (_SyncRoot)
				{
					if (_InitialProgress == value)
						return;
					_InitialProgress = value;
					if (_State != TaskState.Initializing || _Progress == value)
						return;
					_Progress = value;
				}
				this.ProgressChanged.RaiseEvent(this, new TaskProgressChangedEventArgs(this, _Version, value));
			}
		}
		#endregion
		#region IsCanceling
		/// <summary>
		/// 取得工作是否正在取消。
		/// </summary>
		public bool IsCanceling
		{
			get
			{
				return (_State == TaskState.Canceling);
			}
		}
		#endregion
		#region IsCompleted
		/// <summary>
		/// 取得值以確認工作的狀態是否為 TaskState.Executed、TaskState.Canceled、TaskState.Error 的其中一個。
		/// </summary>
		public bool IsCompleted
		{
			get
			{
				TaskState state = _State;
				switch (state)
				{
					case TaskState.Executed:
					case TaskState.Canceled:
					case TaskState.Error:
						return true;
					default:
						return false;
				}
			}
		}
		#endregion
		#region IsCurrentTaskCanceling
		/// <summary>
		/// 取得值以確認目前的工作是否正在取消。
		/// </summary>
		public static bool IsCurrentTaskCanceling
		{
			get
			{
				Task task = CurrentTask;
				return (task != null && task.IsCanceling);
			}
		}
		#endregion
		#region IsDescendantOf
		/// <summary>
		/// 確認是否為指定工作的子代工作。
		/// </summary>
		/// <param name="task">要確認是否為父代的工作。</param>
		/// <returns>True 表示此工作是 task 的子代工作，False 表示不是。</returns>
		/// <exception cref="ArgumentNullException">task 為 Null (Visual Basic 為 Nothing)。</exception>
		public bool IsDescendantOf(Task task)
		{
			//確認參數
			if (task == null)
				throw new ArgumentNullException("task");

			//確認工作關係
			lock (_SyncRoot)
			{
				if (_ParentTask == task)
					return true;
				return (_ParentTask != null && _ParentTask.IsDescendantOf(task));
			}
		}
		#endregion
		#region IsPreemptable
		/// <summary>
		/// 取得或設定工作的執行時間是否可以被其他工作搶佔，預設值為 True。
		/// </summary>
		public bool IsPreemptable
		{
			get
			{
				return ((_Flags & TaskFlags.IsPreemptable) != 0);
			}
			set
			{
				lock (_SyncRoot)
				{
					//確認狀態
					if (_State != TaskState.Initializing)
						throw new InvalidOperationException();

					//設定
					if (value)
						_Flags |= TaskFlags.IsPreemptable;
					else
						_Flags &= ~TaskFlags.IsPreemptable;
				}
			}
		}
		#endregion
		#region LastMessage
		/// <summary>
		/// 取得最近一次的訊息文字。
		/// </summary>
		public string LastMessage
		{
			get
			{
				return _LastMessage;
			}
		}
		#endregion
		#region LastMessageType
		/// <summary>
		/// 取得最近一次的訊息類型。
		/// </summary>
		public TaskMessageType LastMessageType
		{
			get
			{
				return _LastMessageType;
			}
		}
		#endregion
		#region Logger
		/// <summary>
		/// 取得 Log 紀錄器。
		/// </summary>
		protected NLog.Logger Logger
		{
			get
			{
				if (_Logger == null)
				{
					lock (_SyncRoot)
					{
						if (_Logger == null)
							_Logger = NLog.LogManager.GetLogger(this.GetType().Name);
					}
				}
				return _Logger;
			}
		}
		#endregion
		#region Name
		/// <summary>
		/// 取得或設定工作名稱。
		/// </summary>
		public string Name
		{
			get
			{
				return _Name;
			}
			set
			{
				this.SetInitializingParameter<string>(ref _Name, value);
			}
		}
		#endregion
		#region OnCanceling
		/// <summary>
		/// 引發 Canceling 事件。
		/// </summary>
		/// <param name="e">事件資料。</param>
		protected virtual void OnCanceling(TaskEventArgs e)
		{
			//引發事件
			this.Canceling.RaiseEvent(this, e);
		}
		#endregion
		#region OnChildTaskCompleted
		void OnChildTaskCompleted(Task childTask, TaskVersion parentTaskVersion, TaskState childTaskState)
		{
			lock (_SyncRoot)
			{
				//確認狀態
				if (_Version != parentTaskVersion)
					return;
				if (childTask != _ChildTask)
					return;

				//儲存執行結果
				_ChildTask = null;
				_ChildTaskState = childTaskState;
			}
		}
		#endregion
		#region OnChildTaskMessageCreated
		void OnChildTaskMessageCreated(object sender, TaskMessageEventArgs e)
		{
			Task childTask = (sender as Task);
			lock (_SyncRoot)
			{
				if (_Version != childTask._ParentTaskVersion)
					return;
			}
			this.OnChildTaskMessageCreated(childTask._ParentTaskVersion, childTask, e);
		}
		/// <summary>
		/// 當子工作建立新訊息時，呼叫的方法。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="childTask">建立訊息的子工作。</param>
		/// <param name="e">訊息事件資料。</param>
		protected virtual void OnChildTaskMessageCreated(TaskVersion version, Task childTask, TaskMessageEventArgs e)
		{
			if ((_Flags & TaskFlags.ForwardChildTaskMessage) != 0)
				this.CreateMessage(version, e.MessageType, e.Message);
		}
		#endregion
		#region OnChildTaskProgressChanged
		void OnChildTaskProgressChanged(object sender, TaskProgressChangedEventArgs e)
		{
			Task childTask = (sender as Task);
			lock (_SyncRoot)
			{
				if (_Version != childTask._ParentTaskVersion)
					return;
			}
			this.OnChildTaskProgressChanged(childTask._ParentTaskVersion, childTask, e);
		}
		/// <summary>
		/// 當子工作進度改變時，呼叫的方法。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="childTask">進度變更的子工作。</param>
		/// <param name="e">進度變更事件資料。</param>
		protected virtual void OnChildTaskProgressChanged(TaskVersion version, Task childTask, TaskProgressChangedEventArgs e)
		{ }
		#endregion
		#region OnPropertyChanged
		void OnPropertyChanged(string propertyName)
		{
			PropertyChangedEventHandler handlers = _PropertyChangedHandlers;
			if (handlers != null)
				handlers(this, new PropertyChangedEventArgs(propertyName));
		}
		#endregion
		#region ParentTask
		/// <summary>
		/// 取得父工作。
		/// </summary>
		public Task ParentTask
		{
			get
			{
				return _ParentTask;
			}
		}
		#endregion
		#region Priority
		/// <summary>
		/// 取得或設定工作優先權，預設值為 TaskPriority.Normal。
		/// </summary>
		public TaskPriority Priority
		{
			get
			{
				return _Priority;
			}
			set
			{
				lock (_SyncRoot)
				{
					//確認狀態
					if (_State != TaskState.Initializing)
						throw new InvalidOperationException();

					//確認參數
					if (!Enum.IsDefined(typeof(TaskPriority), value))
						throw new ArgumentException();

					//設定優先權
					_Priority = value;
				}
			}
		}
		#endregion
		#region Progress
		/// <summary>
		/// 取得目前的工作進度，Null (Visual Basic 為 Nothing) 表示工作未執行或進度無法估計。
		/// </summary>
		public double? Progress
		{
			get
			{
				return _Progress;
			}
		}
		#endregion
		#region RaiseEvent
		/// <summary>
		/// 若指定的工作版本與目前的工作版本相同，則引發事件。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="eventHandlers">事件處理的方法列表。</param>
		/// <param name="e">事件資料。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void RaiseEvent(TaskVersion version, EventHandler eventHandlers, EventArgs e)
		{
			//確認版本
			lock (_SyncRoot)
			{
				if (version == null)
					throw new ArgumentNullException("version");
				if (_Version != version)
					return;
			}

			//引發事件
			if (eventHandlers != null)
				eventHandlers(this, e);
		}
		/// <summary>
		/// 若指定的工作版本與目前的工作版本相同，則引發事件。
		/// </summary>
		/// <typeparam name="T">事件資料型別。</typeparam>
		/// <param name="version">工作版本。</param>
		/// <param name="eventHandlers">事件處理的方法列表。</param>
		/// <param name="e">事件資料。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void RaiseEvent<T>(TaskVersion version, EventHandler<T> eventHandlers, T e) where T : EventArgs
		{
			//確認版本
			lock (_SyncRoot)
			{
				if (version == null)
					throw new ArgumentNullException("version");
				if (_Version != version)
					return;
			}

			//引發事件
			if (eventHandlers != null)
				eventHandlers(this, e);
		}
		#endregion
		#region ReadValue
		/// <summary>
		/// 若指定的工作版本與目前的工作版本相同，則從指定的位置讀取資料。
		/// </summary>
		/// <typeparam name="T">資料型別。</typeparam>
		/// <param name="version">工作版本。</param>
		/// <param name="source">資料來源。</param>
		/// <param name="value">讀取的資料。</param>
		/// <returns>True 表示資料讀取成功，False 表示指定的工作版本不是目前的工作版本。</returns>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool ReadValue<T>(TaskVersion version, ref T source, out T value)
		{
			lock (_SyncRoot)
			{
				//確認版本
				if (version == null)
					throw new ArgumentNullException("version");
				if (_Version != version)
				{
					value = default(T);
					return false;
				}

				//讀取資料
				value = source;

				//完成
				return true;
			}
		}
		#endregion
		#region Ready
		internal void Ready()
		{
			lock (_SyncRoot)
			{
				if (_State == TaskState.Initializing)
				{
					if (_DelayedStartTime > 0)
						_ReadyTime = (long)(DateTime.Now - DateTime.MinValue).TotalMilliseconds + _DelayedStartTime;
					else
						_ReadyTime = null;
					this.SetState(TaskState.Ready);
				}
				else
					throw new InvalidOperationException();
			}
		}
		#endregion
		#region ReadyTime
		internal long? ReadyTime
		{
			get
			{
				return _ReadyTime;
			}
		}
		#endregion
		#region ReportProgress
		/// <summary>
		/// 回報工作進度，並引發 ProgressChanged 事件。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="progress">最新的工作進度。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void ReportProgress(TaskVersion version, double? progress)
		{
			//確認狀態
			if (version == null)
				throw new ArgumentNullException("version");

			//修正進度
			if (progress != null)
			{
				if (progress.Value < 0)
					progress = 0;
				else if (progress.Value > 100)
					progress = 100;
			}

			//變更進度
			lock (_SyncRoot)
			{
				//版本確認
				if (_Version != version)
					return;

				//狀態確認
				if ((_State != TaskState.Executing && _State != TaskState.Canceling) || progress == _Progress)
					return;

				//進度確認
				if (_Progress == progress)
					return;

				//變更進度
				_Progress = progress;
			}

			//引發事件
			this.ProgressChanged.RaiseEvent(this, new TaskProgressChangedEventArgs(this, _Version, progress));
			this.OnPropertyChanged("Progress");
		}
		#endregion
		#region Reset
		/// <summary>
		/// 重設工作，讓狀態回到 Initializing。
		/// </summary>
		/// <exception cref="InvalidOperationException">工作尚未完成，即狀態不是 Executed、Canceled、Error 其中之一。</exception>
		public void Reset()
		{
			//重設狀態
			bool isProgressChanged;
			lock (_SyncRoot)
			{
				//確認狀態
				if (_State != TaskState.Canceled && _State != TaskState.Executed && _State != TaskState.Error)
					throw new InvalidOperationException();

				//重設參數
				try
				{
					this.ResetOverride();
				}
				finally
				{
					_Exception = null;
					_Executor = null;
					_Flags &= ~(TaskFlags.HasErrors | TaskFlags.HasWarnings);
					isProgressChanged = (_Progress != _InitialProgress);
					if (isProgressChanged)
						_Progress = _InitialProgress;
				}

				//變更狀態
				this.SetState(TaskState.Initializing);
			}

			//引發事件
			if (isProgressChanged)
				this.ProgressChanged.RaiseEvent(this, new TaskProgressChangedEventArgs(this, _Version, _Progress));
		}
		#endregion
		#region ResetOverride
		/// <summary>
		/// 重設工作狀態。
		/// </summary>
		protected virtual void ResetOverride()
		{ }
		#endregion
		#region SetExecutor
		internal void SetExecutor(TaskExecutor executor)
		{
			lock (_SyncRoot)
			{
				if (executor != null && _Executor != null)
					throw new InvalidOperationException();
				_Executor = executor;
			}
		}
		#endregion
		#region SetInitializingParameter
		/// <summary>
		/// 在狀態為 Initializing 的情況下，設定初始化參數，否則擲出 InvalidOperationException。
		/// </summary>
		/// <typeparam name="T">參數型別。</typeparam>
		/// <param name="param">初始化參數。</param>
		/// <param name="value">初始化參數值。</param>
		/// <exception cref="InvalidOperationException">目前的狀態不是 Initializing。</exception>
		protected void SetInitializingParameter<T>(ref T param, T value)
		{
			lock (_SyncRoot)
			{
				//確認狀態
				if (_State != TaskState.Initializing)
					throw new InvalidOperationException();

				//設定參數
				param = value;
			}
		}
		#endregion
		#region SetParentTask
		void SetParentTask(Task parentTask, TaskVersion parentTaskVersion)
		{
			_ParentTask = parentTask;
			_ParentTaskVersion = parentTaskVersion;
		}
		#endregion
		#region SetState
		bool SetState(TaskState newState)
		{
			//變更狀態
			TaskVersion version;
			lock (_SyncRoot)
			{
				//變更狀態
				if (_State == newState)
					return false;
				_State = newState;
				version = _Version;

				//通知工作已完成
				if ((_State == TaskState.Executed || _State == TaskState.Canceled || _State == TaskState.Error) && _CompletionWaitEvent != null)
				{
					_CompletionWaitEvent.Set();
					_CompletionWaitEvent = null;
				}
			}

			//引發事件
			TaskEventArgs e = new TaskEventArgs(this, version);
			this.StateChanged.RaiseEvent(this, e);
			this.OnPropertyChanged("State");
			switch (newState)
			{
				case TaskState.Executed:
				case TaskState.Canceled:
				case TaskState.Error:
					this.Completed.RaiseEvent(this, e);
					break;
			}

			//回傳
			return true;
		}
		#endregion
		#region State
		/// <summary>
		/// 取得工作目前的狀態。
		/// </summary>
		public TaskState State
		{
			get
			{
				return _State;
			}
		}
		#endregion
		#region SyncRoot
		/// <summary>
		/// 取得內部提供同步控制的物件。
		/// </summary>
		internal protected object SyncRoot
		{
			get
			{
				return _SyncRoot;
			}
		}
		#endregion
		#region UpdateVersion
		TaskVersion UpdateVersion()
		{
			TaskVersion oldVersion = _Version;
			_Version = new TaskVersion(this, _VersionNumber++);
			return oldVersion;
		}
		#endregion
		#region ValidateInitParameters
		/// <summary>
		/// 驗證初始化參數是否正確。
		/// </summary>
		/// <returns>True 表示所有初始化參數皆正確，False 表示不完全正確。</returns>
		protected virtual bool ValidateInitParameters()
		{
			return true;
		}
		#endregion
		#region WaitForChildTask
		/*
		TaskState? WaitForChildTask()
		{
			//確認狀態
			Task childTask;
			TaskExecutionThread execThread;
			lock (_SyncRoot)
			{
				childTask = _ChildTask;
				execThread = _ExecutionThread;
				if (childTask == null)
					return null;
			}

			//等待子工作完成
			while (true)
			{
				//切換工作
				execThread.ExecuteTask(false);

				//確認子工作是否已完成
				while (!Monitor.TryEnter(_SyncRoot))
					Thread.Yield();
				try
				{
					if (_ChildTaskState != null)
					{
						//紀錄子工作結果
						TaskState state = _ChildTaskState.Value;

						//取消事件連結
						childTask.MessageCreated -= this.OnChildTaskMessageCreated;
						childTask.ProgressChanged -= this.OnChildTaskProgressChanged;

						//重設資料
						_ChildTask = null;
						_ChildTaskState = null;

						//完成
						return state;
					}
				}
				finally
				{
					Monitor.Exit(_SyncRoot);
				}
				Thread.Yield();
			}
		}
		*/
		#endregion
		#region WaitForCompletion
		/// <summary>
		/// 等待工作完成，即狀態為 Executed、Canceled、Error 其中一個。
		/// </summary>
		public void WaitForCompletion()
		{
			this.WaitForCompletion(Timeout.Infinite);
		}
		/// <summary>
		/// 等待工作完成，即狀態為 Executed、Canceled、Error 其中一個。
		/// </summary>
		/// <param name="timeout">最長等待時間，單位為毫秒。</param>
		/// <returns>True 表示工作已在指定時間內結束，False 表示尚未結束。</returns>
		/// <exception cref="ArgumentOutOfRangeException">timeout 為負值，且不等於 Timeout.Infinite。</exception>
		public bool WaitForCompletion(int timeout)
		{
			TaskState state;
			return this.WaitForCompletion(timeout, out state);
		}
		bool WaitForCompletion(int timeout, out TaskState state)
		{
			//建立 WaitHandle
			TaskExecutionThread executionThread = TaskExecutionThread.CurrentThread;
			TaskExecutor executor = (executionThread != null ? executionThread.Executor : null);
			WaitEvent waitEvent;
			lock (_SyncRoot)
			{
				//確認狀態
				if (_State == TaskState.Executed || _State == TaskState.Canceled || _State == TaskState.Error)
				{
					state = _State;
					return true;
				}

				//立即回傳
				if (timeout == 0)
				{
					state = _State;
					return false;
				}

				//建立 WaitEvent
				if ((executionThread == null || executor != _Executor || (executor != null && executor.MaxThreads > 1)) &&
					(executionThread == null || !this.IsDescendantOf(executionThread.CurrentTask)))
				{
					waitEvent = _CompletionWaitEvent;
					if (waitEvent == null)
					{
						waitEvent = new WaitEvent();
						_CompletionWaitEvent = waitEvent;
					}
				}
				else
					waitEvent = null;
			}

			//等待
			if (waitEvent != null)
			{
				//等待執行完成
				if (waitEvent.Wait(timeout))
				{
					state = _State;
					return true;
				}

				//超過等待時間
				state = _State;
				return false;
			}
			else
			{
				//建立計時器
				Stopwatch stopWatch;
				if (timeout > 0)
				{
					stopWatch = new Stopwatch();
					stopWatch.Start();
				}
				else
					stopWatch = null;

				//優先執行此工作
				_Executor.MoveTaskToFrontOfQueue(this);

				//開始等待
				try
				{
					while (true)
					{
						//確認是否已完成
						lock (_SyncRoot)
						{
							state = _State;
							if (_State == TaskState.Executed || _State == TaskState.Canceled || _State == TaskState.Error)
								return true;
						}

						//確認是否已逾時
						if (timeout == 0)
							return false;
						if (stopWatch != null && stopWatch.ElapsedMilliseconds >= timeout)
							return false;

						//切換工作
						executionThread.ExecuteTask(false, null);
					}
				}
				finally
				{
					//停止計時
					if (stopWatch != null)
						stopWatch.Stop();
				}
			}
		}
		/// <summary>
		/// 等待指定的工作完成，即狀態為 Executed、Canceled、Error 其中一個。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="task">指定等待的工作。</param>
		/// <returns>True 表示工作已在指定時間內結束，False 表示尚未結束 -或- 目前的工作已經取消。</returns>
		/// <exception cref="ArgumentException">task 為目前的工作。</exception>
		/// <exception cref="ArgumentNullException">version 或 task 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool WaitForCompletion(TaskVersion version, Task task)
		{
			return this.WaitForCompletion(version, task, Timeout.Infinite);
		}
		/// <summary>
		/// 等待指定的工作完成，即狀態為 Executed、Canceled、Error 其中一個。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="task">指定等待的工作。</param>
		/// <param name="timeout">最長等待時間，單位為毫秒。</param>
		/// <returns>True 表示工作已在指定時間內結束，False 表示尚未結束 -或- 目前的工作已經取消。</returns>
		/// <exception cref="ArgumentException">task 為目前的工作。</exception>
		/// <exception cref="ArgumentNullException">version 或 task 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool WaitForCompletion(TaskVersion version, Task task, int timeout)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (task == null)
				throw new ArgumentNullException("task");
			if (task == this)
				throw new ArgumentException();

			//直接等待
			if (task._Executor == _Executor)
				return task.WaitForCompletion(timeout);

			//等待工作完成
			return this.DoAction(new Action(() =>
			{
				task.WaitForCompletion();
			}), timeout);
		}
		#endregion
		#region WriteValue
		/// <summary>
		/// 若指定的工作版本與目前的工作版本相同，則將資料寫入指定的位置。
		/// </summary>
		/// <typeparam name="T">資料型別。</typeparam>
		/// <param name="version">工作版本。</param>
		/// <param name="destination">寫入的位置。</param>
		/// <param name="value">寫入的資料。</param>
		/// <returns>True 表示資料寫入成功，False 表示指定的工作版本不是目前的工作版本。</returns>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool WriteValue<T>(TaskVersion version, ref T destination, T value)
		{
			lock (_SyncRoot)
			{
				//確認版本
				if (version == null)
					throw new ArgumentNullException("version");
				if (_Version != version)
				{
					value = default(T);
					return false;
				}

				//寫入資料
				destination = value;

				//完成
				return true;
			}
		}
		#endregion
		#region Yield
		/// <summary>
		/// 暫停目前的工作，讓執行緒立即執行其他可被執行的工作。
		/// </summary>
		/// <returns>True 表示執行緒已執行其他工作，False 表示執行緒未執行其他工作。</returns>
		/// <exception cref="InvalidOperationException">工作狀態不是 Executing 及 Canceling。</exception>
		public static bool Yield()
		{
			return Yield(false);
		}
		/// <summary>
		/// 暫停目前的工作，讓執行緒立即執行其他可被執行的工作。
		/// </summary>
		/// <param name="higherPriorityOnly">是否只執行更高優先權的工作。</param>
		/// <returns>True 表示執行緒已執行其他工作，False 表示執行緒未執行其他工作。</returns>
		/// <exception cref="InvalidOperationException">工作狀態不是 Executing 及 Canceling。</exception>
		public static bool Yield(bool higherPriorityOnly)
		{
			//取的執行續
			TaskExecutionThread executionThread = TaskExecutionThread.CurrentThread;
			if (executionThread == null)
				return false;

			//取得工作
			Task currentTask = executionThread.CurrentTask;
			if (currentTask == null)
				return false;

			//確認是否可被搶佔
			if ((currentTask._Flags & TaskFlags.IsPreemptable) == 0)
				return false;

			//確認優先權
			TaskPriority? minPriority = (higherPriorityOnly ? TaskExecutor.GetHigherPriority(currentTask.Priority) : (TaskPriority?)null);

			//執行其他工作
			return executionThread.ExecuteTask(false, minPriority);
		}
		#endregion
		#region 事件
		/// <summary>
		/// 發生在工作開始取消後。
		/// </summary>
		public event EventHandler<TaskEventArgs> Canceling;
		event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
		{
			add
			{
				_PropertyChangedHandlers += value;
			}
			remove
			{
				_PropertyChangedHandlers -= value;
			}
		}
		/// <summary>
		/// 發生在工作狀態變更為 TaskState.Executed、TaskState.Canceled 或 TaskState.Error 其中一個後。
		/// </summary>
		public event EventHandler<TaskEventArgs> Completed;
		/// <summary>
		/// 發生在產生新的訊息後。
		/// </summary>
		public event EventHandler<TaskMessageEventArgs> MessageCreated;
		/// <summary>
		/// 發生在工作進度改變後。
		/// </summary>
		public event EventHandler<TaskProgressChangedEventArgs> ProgressChanged;
		/// <summary>
		/// 發生在工作狀態改變後。
		/// </summary>
		public event EventHandler<TaskEventArgs> StateChanged;
		#endregion
	}
	#endregion
	#region TaskEventArgs
	/// <summary>
	/// 提供工作相關事件的資料。
	/// </summary>
	public class TaskEventArgs : EventArgs
	{
		#region 欄位
		Task _Task;
		TaskVersion _Version;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 TaskEventArgs 執行個體。
		/// </summary>
		/// <param name="task">與事件相關的工作。</param>
		public TaskEventArgs(Task task)
			: this(task, null)
		{ }
		/// <summary>
		/// 初始化新的 TaskEventArgs 執行個體。
		/// </summary>
		/// <param name="task">與事件相關的工作。</param>
		/// <param name="version">與事件相關的工作版本。</param>
		public TaskEventArgs(Task task, TaskVersion version)
		{
			_Task = task;
			version = _Version;
		}
		#endregion
		#region Task
		/// <summary>
		/// 取得與事件相關的工作。
		/// </summary>
		public Task Task
		{
			get
			{
				return _Task;
			}
		}
		#endregion
		#region TaskVersion
		/// <summary>
		/// 取得與事件相關的工作版本。
		/// </summary>
		public TaskVersion Version
		{
			get
			{
				return _Version;
			}
		}
		#endregion
	}
	#endregion
	#region TaskFlags
	[Flags]
	enum TaskFlags
	{
		ForwardChildTaskMessage = 0x1,
		HasErrors = 0x2,
		HasWarnings = 0x4,
		IsPreemptable = 0x8,
	}
	#endregion
	#region TaskMessageEventArgs
	/// <summary>
	/// 提供工作訊息相關事件的資料。
	/// </summary>
	public class TaskMessageEventArgs : TaskEventArgs
	{
 		#region 欄位
		string _Message;
		TaskMessageType _MessageType;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 TaskMessageEventArgs 執行個體。
		/// </summary>
		/// <param name="task">與事件相關的工作。</param>
		/// <param name="version">與事件相關的工作版本。</param>
		/// <param name="messageType">訊息類型。</param>
		/// <param name="message">訊息內容。</param>
		public TaskMessageEventArgs(Task task, TaskVersion version, TaskMessageType messageType, string message)
			: base(task, version)
		{
			_Message = message;
			_MessageType = messageType;
		}
		#endregion
		#region Message
		/// <summary>
		/// 取得工作的訊息。
		/// </summary>
		public string Message
		{
			get
			{
				return _Message;
			}
		}
		#endregion
		#region MessageType
		/// <summary>
		/// 取得工作訊息的類型。
		/// </summary>
		public TaskMessageType MessageType
		{
			get
			{
				return _MessageType;
			}
		}
		#endregion
	}
	#endregion
	#region TaskMessageType
	/// <summary>
	/// 表示工作訊息的類型。
	/// </summary>
	public enum TaskMessageType
	{
		/// <summary>
		/// 訊息。
		/// </summary>
		Information,
		/// <summary>
		/// 警告。
		/// </summary>
		Warning,
		/// <summary>
		/// 錯誤。
		/// </summary>
		Error,
	}
	#endregion
	#region TaskPriority
	/// <summary>
	/// 表示工作的優先權。
	/// </summary>
	public enum TaskPriority
	{
		/// <summary>
		/// 一般優先權。
		/// </summary>
		Normal = 10,
		/// <summary>
		/// 高優先權。
		/// </summary>
		High = 5,
		/// <summary>
		/// 低優先權。
		/// </summary>
		Low = 15,
	}
	#endregion
	#region TaskProgressChangedEventArgs
	/// <summary>
	/// 提供 Task.ProgressChanged 事件資料。
	/// </summary>
	public class TaskProgressChangedEventArgs : TaskEventArgs
	{
		#region 欄位
		double? _Progress;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 TaskProgressChangedEventArgs 執行個體。
		/// </summary>
		/// <param name="task">與事件相關的工作。</param>
		/// <param name="version">與事件相關的工作版本。</param>
		/// <param name="progress">工作進度百分比。</param>
		public TaskProgressChangedEventArgs(Task task, TaskVersion version, double? progress)
			: base(task, version)
		{
			_Progress = progress;
		}
		#endregion
		#region Progress
		/// <summary>
		/// 取得工作進度。
		/// </summary>
		public double? Progress
		{
			get
			{
				return _Progress;
			}
		}
		#endregion
	}
	#endregion
	#region TaskState
	/// <summary>
	/// 表示工作的狀態。
	/// </summary>
	public enum TaskState
	{
		/// <summary>
		/// 正在初始化。
		/// </summary>
		Initializing,
		/// <summary>
		/// 準備執行。
		/// </summary>
		Ready,
		/// <summary>
		/// 正在執行。
		/// </summary>
		Executing,
		/// <summary>
		/// 執行完成。
		/// </summary>
		Executed,
		/// <summary>
		/// 正在取消。
		/// </summary>
		Canceling,
		/// <summary>
		/// 已經取消。
		/// </summary>
		Canceled,
		/// <summary>
		/// 發生錯誤。
		/// </summary>
		Error,
	}
	#endregion
	#region TaskVersion
	/// <summary>
	/// 表示一個工作的版本。
	/// </summary>
	public class TaskVersion
	{
		#region 欄位
		Task _Task;
		int _Version;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 TaskVersion 執行個體。
		/// </summary>
		/// <param name="task">所屬的工作。</param>
		/// <param name="version">工作的版本。</param>
		/// <exception cref="ArgumentNullException">task 為 Null (Visual Basic 為 Nothing)。</exception>
		public TaskVersion(Task task, int version)
		{
			//確認
			if (task == null)
				throw new ArgumentNullException("task");

			//初始化
			_Task = task;
			_Version = version;
		}
		#endregion
		#region operator ==
		public static bool operator ==(TaskVersion x, TaskVersion y)
		{
			if (!object.ReferenceEquals(x, null))
			{
				if (!object.ReferenceEquals(y, null))
					return (x._Task == y._Task && x._Version == y._Version);
				return false;
			}
			return !object.ReferenceEquals(y, null);
		}
		#endregion
		#region operator !=
		public static bool operator !=(TaskVersion x, TaskVersion y)
		{
			if (!object.ReferenceEquals(x, null))
			{
				if (!object.ReferenceEquals(y, null))
					return (x._Task != y._Task || x._Version != y._Version);
				return true;
			}
			return !object.ReferenceEquals(y, null);
		}
		#endregion
		#region Equals
		/// <summary>
		/// 和指定的物件比較是否相等。
		/// </summary>
		/// <param name="obj">指定的物件。</param>
		/// <returns>是否相等。</returns>
		public override bool Equals(object obj)
		{
			return (this == (obj as TaskVersion));
		}
		#endregion
		#region GetHashCode
		/// <summary>
		/// 取得雜湊值。
		/// </summary>
		/// <returns>雜湊值。</returns>
		public override int GetHashCode()
		{
			return (_Task.GetHashCode() * _Version.GetHashCode());
		}
		#endregion
		#region Task
		/// <summary>
		/// 取得所屬的工作。
		/// </summary>
		public Task Task
		{
			get
			{
				return _Task;
			}
		}
		#endregion
		#region Version
		/// <summary>
		/// 取得工作的版本。
		/// </summary>
		public int Version
		{
			get
			{
				return _Version;
			}
		}
		#endregion
	}
	#endregion
}
